package utils

/***
  fifo queue
  可以设置最大队列数量, 如果超出最大数量将会移除掉第一个
  非纤程安全
*/

type QueueMax struct {
	dlist          *DLinklist
	max_queue_size int
	OnRemoveFunc   func(sender *QueueMax, val interface{}) // Pop和Push, Range都有可能触发
}

func NewQueueMax() *QueueMax {
	rval := &QueueMax{
		dlist: NewDlinklist(),
	}
	return rval
}

func (this *QueueMax) Count() int32 {
	return this.dlist.cnt
}

func (this *QueueMax) GetMaxQueueSize() int {
	return this.max_queue_size
}

func (this *QueueMax) ConfigMaxQueueSize(size int) *QueueMax {
	this.max_queue_size = size
	return this
}

/*
**

	检测最后n个元素是否连续matchfunc, 倒序比较
	CheckMatchN(3,MatchFunc_Down_Float) // 判断最后三个值是否连续下降
*/
func (this *QueueMax) CheckMatchN(n int, matchfunc func(v0, v1 interface{}) bool) (rval bool) {
	if n > int(this.dlist.cnt) {
		return false
	}
	v1 := this.FetchLast()
	var v0 interface{}
	n--
	for n > 0 {
		v0 = this.FetchPre()
		rval = matchfunc(v0, v1)
		if !rval {
			break
		}
		v1 = v0 // 替换到前一个 以便进行下一次比较
		n--
	}
	return
}

func (this *QueueMax) Push(val interface{}) {
	node := NewDlinknodeFromPool()
	node.Value = val
	if this.max_queue_size >= 0 && int(this.dlist.cnt) >= this.max_queue_size {
		node := this.dlist.RemoveFirst()
		if node != nil {
			if this.OnRemoveFunc != nil {
				this.OnRemoveFunc(this, node.Value)
			}
			node.Value = nil
			node.release2Pool() // 归还node
		}
	}
	this.dlist.Append(node)
}

func (this *QueueMax) FetchPre() (rval interface{}) {
	node := this.dlist.FetchPre()
	if node == nil {
		return nil
	}
	return node.Value
}

func (this *QueueMax) FetchLast() (rval interface{}) {
	node := this.dlist.SeekLast()
	if node == nil {
		return nil
	}
	return node.Value
}

func (this *QueueMax) PeekLast() (rval []interface{}) {
	this.Range(func(idx int, value interface{}, removeit *bool) bool {
		rval = append(rval, value)
		return true
	})
	return
}

func (this *QueueMax) PeekAll() (rval []interface{}) {
	this.Range(func(idx int, value interface{}, removeit *bool) bool {
		rval = append(rval, value)
		return true
	})
	return
}

/**
 * Peek第一个
 */
func (this *QueueMax) Peek() (bool, interface{}) {
	node := this.dlist.SeekFirst()
	if node != nil {
		rval := node.Value // 暂存
		return true, rval
	} else {
		return false, nil
	}
}

/**
 * 弹出第一个
 */
func (this *QueueMax) Pop() (bool, interface{}) {
	node := this.dlist.RemoveFirst()
	if node != nil {
		rval := node.Value // 暂存
		if this.OnRemoveFunc != nil {
			this.OnRemoveFunc(this, node.Value)
		}
		node.Value = nil
		node.release2Pool() // 归还node
		return true, rval
	} else {
		return false, nil
	}
}

func (this *QueueMax) Range(cb func(idx int, value interface{}, removeit *bool) bool) {
	this.dlist.RangeEx(cb, func(node *DLinkNode) {
		if this.OnRemoveFunc != nil {
			this.OnRemoveFunc(this, node.Value)
		}
		node.Value = nil
		node.release2Pool()
	})
}

func MatchFunc_Down_Float(v0, v1 interface{}) bool {
	f0 := GetFloat64Value(v0, 0)
	f1 := GetFloat64Value(v1, 0)
	return f0 > f1
}

func MatchFunc_NotDown_Float(v0, v1 interface{}) bool {
	f0 := GetFloat64Value(v0, 0)
	f1 := GetFloat64Value(v1, 0)
	return f0 <= f1
}
